package com.snow.springboot.config;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.Properties;

/**
 * @Package: com.taikanglife.bms.config
 * @ClassName: MybatisConfig
 * @Description: mybatis初始化配置
 * @Author lurui04
 * @Date: 2017/6/8 10:46
 */
@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = "com.snow.springboot.dao")
public class MybatisConfig {
    @Value("${jdbc.driverClassName}")
    private String driverClassName;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Value("${mybatis.typeAliasesPackage}")
    private String typeAliasesPackage;
    @Value("${mybatis.mapperLocations}")
    private String mapperLocations;

    /**
     * 配置参考：https://github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7%BD%AE
     *
     * @Title: getDataSource
     * @Description: 创建数据源datasource
     * @Param: []
     * @Return: javax.sql.DataSource
     * @Date: 2017/6/8 10:46
     * @Author: lurui04
     */
    @Bean(name = "dataSource")
    public DataSource getDataSource() throws Exception {
        Properties props = new Properties();
        props.put("driverClassName", driverClassName);
        props.put("url", url);
        props.put("username", username);
        props.put("password", password);
        props.put("initialSize", "10");
        props.put("minIdle", "10");
        props.put("maxActive", "20");
        props.put("maxWait", "60000");
        props.put("filters", "stat,wall,slf4j");
        props.put("validationQuery", "SELECT 'x'");
        props.put("testWhileIdle", "true");
        //配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒
        props.put("timeBetweenEvictionRunsMillis", "60000");
        // 配置一个连接在池中最小生存的时间，单位是毫秒
        props.put("minEvictableIdleTimeMillis", "300000");
        //设置为true以后影响性能
        props.put("testOnBorrow", "true");
        props.put("testOnReturn", "false");


        //在每次空闲连接回收器线程(如果有)运行时检查的连接数量，最好和maxActive一致
        //props.put("numTestsPerEvictionRun", "20");
        /**
         * 连接泄露监测：https://github.com/alibaba/druid/wiki/%E8%BF%9E%E6%8E%A5%E6%B3%84%E6%BC%8F%E7%9B%91%E6%B5%8B
         */
        // 配置removeAbandoned对性能会有一些影响，建议怀疑存在泄漏之后再打开，如果连接超过30分钟未关闭，就会被强行回收，并且日志记录连接申请时的调用堆栈。
        //连接泄漏回收参数，当可用连接数少于3个时才执行
        // props.put("removeAbandoned", "true");
        //连接泄漏回收参数，1800秒，泄露的连接可以被删除的超时值
        // props.put("removeAbandonedTimeout", "1800");
        return DruidDataSourceFactory.createDataSource(props);
    }

    /**
     * @Title: sqlSessionFactory
     * @Description: 根据数据源创建SqlSessionFactory
     * @Param: [ds]
     * @Return: org.apache.ibatis.session.SqlSessionFactory
     * @Date: 2017/6/8 10:46
     * @Author: lurui04
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
        fb.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
        //指定数据源
        fb.setDataSource(getDataSource());
        //指定基包
        fb.setTypeAliasesPackage(typeAliasesPackage);
        //指定xml文件位置
        fb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
        return fb.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory());
    }


    @Bean
    public DataSourceTransactionManager transactionManager() throws Exception {
        return new DataSourceTransactionManager(getDataSource());
    }


    /**
     * 注册一个StatViewServlet
     *
     * @return
     */
    @Bean
    public ServletRegistrationBean DruidStatViewServlet() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
        /** 用户名 */
        servletRegistrationBean.addInitParameter("loginUsername", "lurui04");
        /** 密码 */
        servletRegistrationBean.addInitParameter("loginPassword", "Lurui_123456");
        /** 禁用页面上的“Reset All”功能 */
        servletRegistrationBean.addInitParameter("resetEnable", "false");
        return servletRegistrationBean;
    }

    /**
     * 注册一个：WebStatFilter
     *
     * @return
     */
    @Bean
    public FilterRegistrationBean druidStatFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
        /** 过滤规则 */
        filterRegistrationBean.addUrlPatterns("/*");
        /** 忽略资源 */
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid2/*");
        return filterRegistrationBean;
    }


}
